package com.applink.sell_proof.util;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Calendar;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import android.os.Environment;

public class SimpleCrypto {
	
	private static String seedUserFrequency = "APLINK";
	private static String encryptedFileName = "sellproof.log";
	
	
	public static String encrypt(String seed, String cleartext) throws Exception {
	        byte[] rawKey = getRawKey(seed.getBytes());
	        byte[] result = encrypt(rawKey, cleartext.getBytes());
	        return toHex(result);
	}
	
	public static String decrypt(String seed, String encrypted) throws Exception {
	        byte[] rawKey = getRawKey(seed.getBytes());
	        byte[] enc = toByte(encrypted);
	        byte[] result = decrypt(rawKey, enc);
	        return new String(result);
	}
	
	private static byte[] getRawKey(byte[] seed) throws Exception {
	        KeyGenerator kgen = KeyGenerator.getInstance("AES");
	        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
	        sr.setSeed(seed);
	    kgen.init(128, sr); // 192 and 256 bits may not be available
	    SecretKey skey = kgen.generateKey();
	    byte[] raw = skey.getEncoded();
	    return raw;
	}
	
	
	private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
	    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
	        Cipher cipher = Cipher.getInstance("AES");
	    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
	    byte[] encrypted = cipher.doFinal(clear);
	        return encrypted;
	}
	
	private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
	    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
	        Cipher cipher = Cipher.getInstance("AES");
	    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
	    byte[] decrypted = cipher.doFinal(encrypted);
	        return decrypted;
	}
	
	public static String toHex(String txt) {
	        return toHex(txt.getBytes());
	}
	public static String fromHex(String hex) {
	        return new String(toByte(hex));
	}
	
	public static byte[] toByte(String hexString) {
	        int len = hexString.length()/2;
	        byte[] result = new byte[len];
	        for (int i = 0; i < len; i++)
	                result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
	        return result;
	}
	
	public static String toHex(byte[] buf) {
	        if (buf == null)
	                return "";
	        StringBuffer result = new StringBuffer(2*buf.length);
	        for (int i = 0; i < buf.length; i++) {
	                appendHex(result, buf[i]);
	        }
	        return result.toString();
	}
	private final static String HEX = "0123456789ABCDEF";
	private static void appendHex(StringBuffer sb, byte b) {
	        sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
	}
	
	public static ArrayList<String> getUserLog(String contactId) {
		
		 ArrayList<String> finalResult = new ArrayList<String>();
		
		 //we firstly and fetch into the String builder to get raw data
		 StringBuilder clearContent = new StringBuilder("");
		 clearContent = SimpleCrypto.getRawDataFromEncryptedFile();
		 
		
		 if(clearContent != null && clearContent.toString().compareTo("")!=0){
			 
			 String []subUsers = clearContent.toString().split(";");
			 //secondly, we check with contactId	 
			 for(int i=0;i <subUsers.length;i++){
				 if(subUsers[i].contains(contactId) == true){
					 finalResult.add(subUsers[i]);
				 }
			 }
		 }
		 
		//delete the file
		 File encryptedFile = new File(Environment.getExternalStorageDirectory()
	             +File.separator
	             +"SellProof" //folder name
	             +File.separator
	             +SimpleCrypto.encryptedFileName); //file name
	    		    
	     if(encryptedFile.exists()){ 
	    	 encryptedFile.delete();
	     }
		 
		return finalResult;
	}
		
	public static boolean activeUserLog(String userId){
		 
		 boolean isSuccessful = false;

		 StringBuilder clearContent = new StringBuilder();
		 clearContent = SimpleCrypto.getRawDataFromEncryptedFile();
		 
		 if(clearContent == null){
			 return false; 
		 }
		 
		//we append new data in raw file
		 Calendar currentCal = Calendar.getInstance();
		 	int newyear = currentCal.get(Calendar.YEAR);
			int newmonth = currentCal.get(Calendar.MONTH)+1;
			int newday = currentCal.get(Calendar.DAY_OF_MONTH);
			int newhourofday = currentCal.get(Calendar.HOUR_OF_DAY);
			int newminute = currentCal.get(Calendar.MINUTE);
			int newmilisecond = currentCal.get(Calendar.SECOND);
		
		//finally we encrypt it again and write back into the file
		 String newRecord = String.valueOf(newmonth) + "-" + 
		 				   String.valueOf(newday) + "-" + 
						   String.valueOf(newyear)  +  " " +  
						   String.valueOf(newhourofday) + ":" + 
						   String.valueOf(newminute) + ":" + 
						   String.valueOf(newmilisecond) + "/" + 
						   userId  + ";";
		 
		 clearContent.append(newRecord);
		 
		 isSuccessful = encryptRawDataIntoFile(clearContent);
		
        //to pull data from sdcard into ws
		return isSuccessful;
		
	}

	
	private static byte[] getKeyBytes(final byte[] key) throws Exception {
        byte[] keyBytes = new byte[16];
        System.arraycopy(key, 0, keyBytes, 0, Math.min(key.length, keyBytes.length));
        return keyBytes;
    }

    public static Cipher getCipherEncrypt(final byte[] key) throws Exception {
        byte[] keyBytes = getKeyBytes(key);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//AES/CFB8/NoPadding
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        return cipher;
    }

    public static Cipher getCipherDecrypt(byte[] key) throws Exception {
        byte[] keyBytes = getKeyBytes(key);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        return cipher;
    }
    
    
	private static boolean encryptRawDataIntoFile(StringBuilder rawData) {
		boolean isSuccessful = false;
		
		if(rawData == null)
			return false;
	
	    try {
	    	if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
		        //handle case of no SDCARD present
		    } else {
		        File encryptedFile = new File(Environment.getExternalStorageDirectory()
		             +File.separator
		             +"SellProof" //folder name
		             +File.separator
		             +SimpleCrypto.encryptedFileName); //file name
		    
		    	/***
			     * we must create the new file in this folder in any case
			     */
			    
		        if(!encryptedFile.exists()){ 
		        	encryptedFile.createNewFile();	//create the file
		        } else {
		        	encryptedFile.delete();
		        	encryptedFile.createNewFile();	//create the file
		        }
		       
		        FileOutputStream fos = new FileOutputStream(encryptedFile);
			    
		        
		        //firstly we encrypt the data 
		     	/***
		    	 * We must write encrypt content and save in theFile
		    	 */
		        // getRawKey from seed
			    byte[] rawKey = getRawKey(SimpleCrypto.seedUserFrequency.getBytes());
			    Cipher cipher = getCipherEncrypt(rawKey);
			    
			    
			    // create the inputstream of clearContent
			    // convert String into InputStream
				InputStream is = new ByteArrayInputStream(rawData.toString().getBytes());
				
			    // Wrap the output stream
			    CipherOutputStream cos = new CipherOutputStream(fos, cipher);
			    // Write bytes
			    
			    //fos.write(cipher.doFinal(rawData.toString().getBytes()));
			    byte[] d = new byte[1024];
			    int b = is.read(d);
	            while (b != -1) {
	                cos.write(d, 0, b);
	                b = is.read(d);
	                System.out.println(new String(d, "UTF-8").trim());
	            }
	            
			   
			   /* int b;
			    byte[] d = new byte[1024];
			    while((b = is.read(d)) != -1) {
			        cos.write(d, 0, b);
			    }*/
			    cos.flush();
			    
				 if (cos != null) {
			           cos.close();
			        }
			     if (fos != null) {
			           fos.close();
			     }
			     if (is != null) {
			          is.close();
			     }
			        
				
		    }  
		   
		} catch (Exception e) {
			e.printStackTrace();
			isSuccessful = false;
		}

		return isSuccessful;
	}

	public static StringBuilder getRawDataFromEncryptedFile(){
		
		StringBuilder clearContent = new StringBuilder();
	    try {
	    	if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
		        //handle case of no SDCARD present
		    } else {
		        File encryptedFile = new File(Environment.getExternalStorageDirectory()
		             +File.separator
		             +"SellProof" //folder name
		             +File.separator
		             +SimpleCrypto.encryptedFileName); //file name
		    
		    	//In the first time, the encrypted file doesn't exist
			   
			    	/***
			    	 * we must create the file in this folder
			    	 */
			    
		        if(!encryptedFile.exists()){ 
		        	encryptedFile.getParentFile().mkdir();
		        	encryptedFile.createNewFile();	//create the file
		        	return clearContent;
		        }
		        
		        Calendar cal = Calendar.getInstance(); //this code is to create an unique file name
		        String idString = String.valueOf(cal.getTimeInMillis());
		        
		        File decryptedFile = new File(Environment.getExternalStorageDirectory()
			             +File.separator
			             +"SellProof" //folder name
			             +File.separator
			             +idString+".log"); //file name
			    //we create the new file
		        decryptedFile .createNewFile();	//create the file
		        
		     	/***
		    	 * Eventually, we must read the encrypted content and decrypt them into clear text and save in decryptedFile
		    	 */
		        // getRawKey from seed
			    byte[] rawKey = getRawKey(SimpleCrypto.seedUserFrequency.getBytes());
			    Cipher cipher = getCipherDecrypt(rawKey);
		        
			    FileInputStream fis = new FileInputStream(encryptedFile);
			    
			    
			    FileOutputStream fos = new FileOutputStream(decryptedFile);
			    
			    //decrypt the file
		        CipherInputStream cis = new CipherInputStream(fis, cipher);
		        
		       
		        
		        //int b;
		        //byte[] d = new byte[1024];
		        
		       // byte[] d= new byte[(int)fis.available()];
		        
		        byte[] d = new byte[1024];
			    int b = cis.read(d);
	            while (b != -1) {
	                fos.write(d, 0, b);
	                b = cis.read(d);
	                System.out.println(new String(d, "UTF-8").trim());
	            }
	            
		        //while((b = cis.read(d)) != -1) {
		        	//write it into the output
		        	//fos.write(d, 0, b);
		       // 	fos.write(d);
		       // }
		        
		        //fos.flush();
		        fos.close();
		        cis.close();
		        fis.close();
		        
		        //we read a gain the clear file and then delete the file
		        FileInputStream fcis = new  FileInputStream(decryptedFile);
		        BufferedReader buf = new BufferedReader(new InputStreamReader(fcis));
		           String readString = new String(); 
		           //just reading each line
		           while((readString = buf.readLine())!= null){
		        	   clearContent.append(readString);
		        	   System.out.print("<<<<<<<<<< Clear data:" + clearContent.toString());
		           }
		           
		        buf.close();
		        fcis.close();
		        decryptedFile.delete(); //delete the file
		        
		        //finally return the String of clear data
		    }
		    
		   
		} catch (Exception e) {
				e.printStackTrace();
			  clearContent = null;
		}
		
		return clearContent;
		
	}
	
	
}
